package com.suredy.core.service;

import java.sql.Types;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.NullPrecedence;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Order;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.type.Type;

/**
 * 编码排序字段
 * 
 * @author VIVID.G
 * @since 2016-9-6
 * @version v0.1
 */
public class MySQlConvertOrder extends Order {

	private static final long serialVersionUID = 1L;

	private String encoding = "GBK";
	private NullPrecedence nullPrecedence;

	public static MySQlConvertOrder asc(String propertyName) {
		return new MySQlConvertOrder(propertyName, true);
	}

	public static MySQlConvertOrder desc(String propertyName) {
		return new MySQlConvertOrder(propertyName, false);
	}

	protected MySQlConvertOrder(String propertyName, boolean ascending) {
		super(propertyName, ascending);
	}

	public MySQlConvertOrder encoding(String encoding) {
		if (!StringUtils.isBlank(encoding))
			this.encoding = encoding;

		return this;
	}

	public MySQlConvertOrder ignoreCase() {
		super.ignoreCase();
		return this;
	}

	public MySQlConvertOrder nulls(NullPrecedence nullPrecedence) {
		super.nulls(nullPrecedence);
		return this;
	}

	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
		final String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, this.getPropertyName());
		final Type type = criteriaQuery.getTypeUsingProjection(criteria, this.getPropertyName());
		final SessionFactoryImplementor factory = criteriaQuery.getFactory();
		final int[] sqlTypes = type.sqlTypes(factory);

		final StringBuilder fragment = new StringBuilder();
		for (int i = 0; i < columns.length; i++) {
			final StringBuilder expression = new StringBuilder();
			boolean lower = false;

			if (this.isIgnoreCase()) {
				final int sqlType = sqlTypes[i];
				lower = sqlType == Types.VARCHAR || sqlType == Types.CHAR || sqlType == Types.LONGVARCHAR;
			}

			if (lower) {
				expression.append(factory.getDialect().getLowercaseFunction()).append('(');
			}

			expression.append("convert(").append(columns[i]).append(" using ").append(this.encoding).append(")");

			if (lower) {
				expression.append(')');
			}

			fragment.append(factory.getDialect().renderOrderByElement(expression.toString(), null, this.isAscending() ? "asc" : "desc", nullPrecedence != null ? nullPrecedence : factory.getSettings().getDefaultNullPrecedence()));

			if (i < columns.length - 1) {
				fragment.append(", ");
			}
		}

		return fragment.toString();
	}

	@Override
	public String toString() {
		return "CONVERT( " + super.getPropertyName() + " USING " + encoding + " ) " + (this.isAscending() ? "asc" : "desc");
	}

}
